package javango.contrib.hibernate;

/**
 * Utility class to standardize pagination.
 * 
 *  Parameters to be passed to the dao.
 *  paginate_by: An integer specifying how many objects should be displayed per page. 
 *  page: The current page number, as an integer. This is 1-based. 
 * 
 *  Parameters to be passed from the dao.
 * results_per_page: The number of objects per page. (Same as the paginate_by parameter.)
 * has_next: A boolean representing whether there’s a next page.
 * has_previous: A boolean representing whether there’s a previous page.
 *
 * next: The next page number, as an integer. If there’s no next page, this will still be an integer representing the theoretical next-page number. This is 1-based.
 * previous: The previous page number, as an integer. This is 1-based.
 * last_on_page: The number of the last result on the current page. This is 1-based.
 * first_on_page: The number of the first result on the current page. This is 1-based.
 * pages: The total number of pages, as an integer.
 * hits: The total number of objects across all pages, not just this page.
 * 
 * @author johns
 *
 */
public class Pagination {

	
	public Pagination(){};
	
	public Pagination(Long paginate_by, Long page, Long hits) {
		this.setPaginate_by(paginate_by);
		this.setPage(page);
		this.setHits(hits);
		update();
	}

	/**
	 * Updates this pagination object's properties for the page starting at first row with total objects.
	 * @param total
	 * @param firstRow
	 */
	protected void update() {
		int currentPage = this.getPage().intValue();
		int rowsPerPage = this.getPaginate_by().intValue();
		int total = this.getHits().intValue();
		
		int firstRow = ((currentPage-1) * rowsPerPage)+1;		
		int lastRow = (firstRow-1 + rowsPerPage) > total ? total : firstRow-1 + rowsPerPage;
		
		this.setHas_next(total > lastRow);
		this.setHas_previous(firstRow > 1);
		this.setFirst_on_page(new Long(firstRow));
		this.setLast_on_page(new Long(lastRow));
		
		Double pagesdbl = new Double(Math.ceil(((double)total) / ((double)rowsPerPage))); 
		this.setPages(new Long(pagesdbl.intValue()));
		
		this.setNext(new Long((currentPage * rowsPerPage) < total ? currentPage + 1 : 22));
		this.setPrevious(new Long(currentPage > 1 ? currentPage-1 : 1));
		
	}
	
	public String toString() {
		StringBuilder b = new StringBuilder();
		b.append("paginate_by: " );
		b.append(paginate_by);
		b.append("; page: ");
		b.append(page);
		b.append("; has_next: ");
		b.append(has_next);
		b.append("; has_previous: ");
		b.append(has_previous);
		b.append("; next: ");
		b.append(next);
		b.append("; previous: ");
		b.append(previous);
		b.append("; last_on_page: ");
		b.append(last_on_page);
		b.append("; first_on_page: ");
		b.append(first_on_page);
		b.append("; pages: ");
		b.append(pages);
		b.append("; hits: ");
		b.append(hits);
		return b.toString();
	}
	/**
	 * An integer specifying how many objects should be displayed per page,  deaults to 20
	 */
	private Long paginate_by = new Long(20);
	
	/**
	 * The current page number, as an integer. This is 1-based.
	 */
	private Long page = new Long(1);
	
	/**
	 * A boolean representing whether there’s a next page.
	 */
	private boolean has_next = false;
	
	/**
	 * A boolean representing whether there’s a previous page.
	 */
	private boolean has_previous =  false;
	
	/**
	 * The next page number, as an integer. This is 1-based.
	 */
	private Long next = new Long(0);
	
	/**
	 * The previous page number, as an integer. This is 1-based.
	 */
	private Long previous = new Long(0);
	
	/**
	 * The number of the last result on the current page. This is 1-based.
	 */
	private Long last_on_page = new Long(0);
	
	/**
	 * first_on_page: The number of the first result on the current page. This is 1-based.
	 */
	private Long first_on_page = new Long(0);
	
	/**
	 * pages: The total number of pages, as an integer.
	 */
	private Long pages = new Long(0);
	
	/**
	 * hits: The total number of objects across all pages, not just this page.
	 */
	private Long hits = new Long(0);

	/**
	 * An integer specifying how many objects should be displayed per page.
	 */
	public Long getPaginate_by() {
		return paginate_by;
	}

	/**
	 * An integer specifying how many objects should be displayed per page.
	 */
	public void setPaginate_by(Long paginate_by) {
		this.paginate_by = paginate_by == null ? new Long(0) : paginate_by;
		update();
	}

	/**
	 * The current page number, as an integer. This is 1-based.
	 */
	public Long getPage() {
		return page;
	}

	/**
	 * The current page number, as an integer. This is 1-based.
	 */
	public void setPage(Long page) {
		this.page = (page == null || page.intValue() < 1) ? new Long(1) : page;
		update();
	}

	/**
	 * A boolean representing whether there’s a next page.
	 */
	public boolean isHas_next() {
		return has_next;
	}

	/**
	 * A boolean representing whether there’s a next page.
	 */
	protected void setHas_next(boolean has_next) {
		this.has_next = has_next;
	}

	/**
	 * A boolean representing whether there’s a previous page.
	 */
	public boolean isHas_previous() {
		return has_previous;
	}

	/**
	 * A boolean representing whether there’s a previous page.
	 */
	protected void setHas_previous(boolean has_previous) {
		this.has_previous = has_previous;
	}

	/**
	 * The previous next number, as an integer. This is 1-based.
	 */
	public Long getNext() {
		return next;
	}

	/**
	 * The previous next number, as an integer. This is 1-based.
	 */
	protected void setNext(Long next) {
		this.next = next;
	}

	/**
	 * The previous page number, as an integer. This is 1-based.
	 */
	public Long getPrevious() {
		return previous;
	}

	/**
	 * The previous page number, as an integer. This is 1-based.
	 */
	protected void setPrevious(Long previous) {
		this.previous = previous;
	}

	/**
	 * The number of the last result on the current page. This is 1-based.
	 */
	public Long getLast_on_page() {
		return last_on_page;
	}

	/**
	 * The number of the last result on the current page. This is 1-based.
	 */
	protected void setLast_on_page(Long last_on_page) {
		this.last_on_page = last_on_page;
	}

	/**
	 * first_on_page: The number of the first result on the current page. This is 1-based.
	 */
	public Long getFirst_on_page() {
		return first_on_page;
	}

	/**
	 * first_on_page: The number of the first result on the current page. This is 1-based.
	 */
	protected void setFirst_on_page(Long first_on_page) {
		this.first_on_page = first_on_page;
	}

	/**
	 * pages: The total number of pages, as an integer.
	 */
	public Long getPages() {
		return pages;
	}

	/**
	 * pages: The total number of pages, as an integer.
	 */
	protected void setPages(Long pages) {
		this.pages = pages;
	}

	/**
	 * hits: The total number of objects across all pages, not just this page.
	 */
	public Long getHits() {
		return hits;
	}

	/**
	 * hits: The total number of objects across all pages, not just this page.
	 */
	public void setHits(Long hits) {
		this.hits = hits == null ? new Long(0) : hits;
		update();
	}	
}
